package com.idealighter.game.games.blackjack.manager;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import com.idealighter.game.core.constant.room.RoomActiveConstant;
import com.idealighter.game.dictionary.dic.BlackjackRoomTypeDic;
import com.idealighter.game.dictionary.domain.BlackjackRoomDomain;
import com.idealighter.game.gamehall.dto.MemInfo;
import com.idealighter.game.games.blackjack.dto.CardInfoDto;
import com.idealighter.game.games.blackjack.dto.CardSeatInfoDto;
import com.idealighter.game.games.blackjack.dto.GameInfoDto;
import com.idealighter.game.games.blackjack.dto.RoomInfo;
import com.idealighter.game.games.blackjack.dto.RoomTypeDetailInfo;
import com.idealighter.game.games.blackjack.dto.SeatInfoDto;
import com.idealighter.game.games.blackjack.dto.SeatInfoForBillDto;
import com.idealighter.game.games.blackjack.dto.SeatInfoForInsuranceDto;
import com.idealighter.game.games.blackjack.message.NoticeEnterTableMsg;
import com.idealighter.game.games.blackjack.message.NoticeExitTableMsg;
import com.idealighter.game.games.blackjack.message.NoticeKickoutRoomMsg;
import com.idealighter.game.games.blackjack.message.NoticeKickoutTableMsg;
import com.idealighter.game.games.blackjack.message.NoticePlayerBetMsg;
import com.idealighter.game.games.blackjack.message.NoticePlayerBetOverMsg;
import com.idealighter.game.games.blackjack.message.NoticePlayerDoubleDownMsg;
import com.idealighter.game.games.blackjack.message.NoticePlayerHitMsg;
import com.idealighter.game.games.blackjack.message.NoticePlayerInsuranceMsg;
import com.idealighter.game.games.blackjack.message.NoticePlayerSplitMsg;
import com.idealighter.game.games.blackjack.message.NoticePlayerStandMsg;
import com.idealighter.game.games.blackjack.message.NoticeStageBankerOpMsg;
import com.idealighter.game.games.blackjack.message.NoticeStageBillMsg;
import com.idealighter.game.games.blackjack.message.NoticeStageDealCardMsg;
import com.idealighter.game.games.blackjack.message.NoticeStageInsuranceBillMsg;
import com.idealighter.game.games.blackjack.message.NoticeStagePlayerOpMsg;
import com.idealighter.game.games.blackjack.message.NoticeStageTimeMsg;
import com.idealighter.game.games.blackjack.message.ResEnterGameHallMsg;
import com.idealighter.game.games.blackjack.message.ResEnterRoomMsg;
import com.idealighter.game.games.blackjack.message.ResExchangeTableMsg;
import com.idealighter.game.games.blackjack.message.ResFastEnterTableMsg;
import com.idealighter.game.games.blackjack.message.ResGameInfoMsg;
import com.idealighter.game.games.blackjack.struct.BlackjackCard;
import com.idealighter.game.games.blackjack.struct.BlackjackCardSeat;
import com.idealighter.game.games.blackjack.struct.BlackjackCardsType;
import com.idealighter.game.games.blackjack.struct.BlackjackRoom;
import com.idealighter.game.games.blackjack.struct.BlackjackSeat;
import com.idealighter.game.games.blackjack.struct.BlackjackTable;
import com.idealighter.game.games.blackjack.struct.GameStatus;
import com.idealighter.game.games.common.AbstractSeat;
import com.idealighter.game.games.common.AbstractTable;
import com.idealighter.game.games.common.RoomState;
import com.idealighter.game.message.core.ResMessage;
import com.idealighter.game.player.manager.PlayerMsgWriter;
import com.idealighter.game.player.struct.Player;
import com.idealighter.utils.check.EmptyUtil;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

@Singleton
public class BlackjackMsgMgr {

  @Inject
  private PlayerMsgWriter msgWriter;
  @Inject
  private BlackjackDataMgr dataMgr;
  @Inject
  private BlackjackRoomTypeDic roomTypeDic;


  /**
   * 房间状态，空闲,普通,拥挤,爆满.
   * 
   * @param room 水浒房间.
   * @return 房间状态.
   */
  private RoomState roomStatus(BlackjackRoom room) {
    int playersNum = room.getPlayers().size();
    BlackjackRoomDomain roomDom = room.getRoomDomain();

    if (playersNum < roomDom.getMaxNum() * roomDom.getFree() / 100) {
      return RoomState.IDLE;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getGeneral() / 100) {
      return RoomState.GENERAL;
    } else if (playersNum < roomDom.getMaxNum() * roomDom.getCrowded() / 100) {
      return RoomState.CROWD;
    } else {
      return RoomState.FULL;
    }
  }

  private RoomInfo getRoomInfoByInstanceId(int instanceId) {
    BlackjackRoom room = dataMgr.getRoomByIntanceId(instanceId);
    BlackjackRoomDomain roomDomain = room.getRoomDomain();
    RoomInfo roomInfo = null;
    if (roomDomain.getIsActive() == RoomActiveConstant.ACTIVE) {
      roomInfo = new RoomInfo();
      roomInfo.setRoomId(room.getId().intValue());
      roomInfo.setName(roomDomain.getName());
      roomInfo.setType(roomDomain.getType());
      roomInfo.setMaxNum(roomDomain.getMaxNum());
      roomInfo.setFree(roomDomain.getFree());
      roomInfo.setGeneral(roomDomain.getGeneral());
      roomInfo.setCrowded(roomDomain.getCrowded());
      roomInfo.setLower(roomDomain.getLower());
      roomInfo.setUpper(roomDomain.getUpper());
      roomInfo.setProportionGold(roomDomain.getProportionGold());
      roomInfo.setProportionChips(roomDomain.getProportionChips());
      roomInfo.setTable(roomDomain.getTableNum());
      roomInfo.setAfee(roomDomain.getAfee());
      roomInfo.setInType(roomDomain.getInType());
      roomInfo.setPlayerNum(room.getPlayers().size());
      roomInfo.setStatus(roomStatus(room).desc);
      roomInfo.setDisplayNames(roomDomain.getDisplays());
      roomInfo.setPlaceHolder(roomDomain.getPlaceHolder());
      roomInfo.setBets(roomDomain.getBets());
      roomInfo.setMaxBet(roomDomain.getMaxBet());
    }
    return roomInfo;
  }

  /**
   * 发送进入大厅消息.
   *
   * @author abin
   * @date 2018年3月21日 下午8:28:31
   * @return
   */
  public ResMessage resEnterGameHallMsg() {
    ResEnterGameHallMsg msg = new ResEnterGameHallMsg();

    Collection<BlackjackRoom> rooms = dataMgr.newestRooms();
    for (BlackjackRoom room : rooms) {
      BlackjackRoomDomain roomDomain = room.getRoomDomain();
      if (roomDomain.getIsActive() != RoomActiveConstant.ACTIVE) {
        continue;
      }
      RoomTypeDetailInfo roomTypeDetailInfo = new RoomTypeDetailInfo();

      roomTypeDetailInfo.setType(roomDomain.getType());
      roomTypeDetailInfo.setTypeName(roomTypeDic.map().get(roomDomain.getType()).getName());

      RoomInfo roomInfo = new RoomInfo();
      roomInfo.setRoomId(room.getId().intValue());
      roomInfo.setName(roomDomain.getName());
      roomInfo.setType(roomDomain.getType());
      roomInfo.setMaxNum(roomDomain.getMaxNum());
      roomInfo.setFree(roomDomain.getFree());
      roomInfo.setGeneral(roomDomain.getGeneral());
      roomInfo.setCrowded(roomDomain.getCrowded());
      roomInfo.setLower(roomDomain.getLower());
      roomInfo.setUpper(roomDomain.getUpper());
      roomInfo.setProportionGold(roomDomain.getProportionGold());
      roomInfo.setProportionChips(roomDomain.getProportionChips());
      roomInfo.setTable(roomDomain.getTableNum());
      roomInfo.setAfee(roomDomain.getAfee());
      roomInfo.setInType(roomDomain.getInType());
      roomInfo.setPlayerNum(room.getPlayers().size());
      roomInfo.setStatus(roomStatus(room).desc);
      roomInfo.setDisplayNames(roomDomain.getDisplays());
      roomInfo.setPlaceHolder(roomDomain.getPlaceHolder());
      roomInfo.setBets(roomDomain.getBets());
      roomInfo.setMaxBet(roomDomain.getMaxBet());
      roomTypeDetailInfo.getRooms().add(roomInfo);

      msg.getRoomTypes().add(roomTypeDetailInfo);
    }


    return msg;
  }

  /**
   * 发送进入桌子消息.
   *
   * @author abin
   * @date 2018年3月21日 下午8:31:30
   * @param player 玩家.
   * @return
   */
  public ResMessage resEnterRoomMsg(Player player) {
    ResEnterRoomMsg msg = new ResEnterRoomMsg();
    for (AbstractTable table : player.curRoom.tables()) {
      msg.getTables().add(table.tableInfo());
    }
    msg.setMembers(player.curRoom.memInfos());
    return msg;
  }

  /**
   * 发送快速进入结果消息.
   */
  public void noticeFastEnterTableMsg(Player player, List<MemInfo> memInfos) {
    ResFastEnterTableMsg msg = new ResFastEnterTableMsg();
    msg.setMems(memInfos);

    msgWriter.writeMsg(player, msg);
  }

  /**
   * 返回快速进入结果消息.
   */
  public ResMessage resFastEnterTableMsg(List<MemInfo> members, long totalChips) {
    ResFastEnterTableMsg msg = new ResFastEnterTableMsg();
    msg.setMems(members);
    msg.setTotalChips(totalChips);
    return msg;
  }

  /**
   * 返回换桌结果消息.
   */
  public ResMessage resExchangeTableMsg(List<MemInfo> members, long totalChips) {
    ResExchangeTableMsg msg = new ResExchangeTableMsg();
    msg.setMems(members);
    msg.setTotalChips(totalChips);
    return msg;
  }


  /**
   * 获取游戏信息 .
   *
   * @author abin
   * @date 2018年3月29日 下午2:58:30
   * @param player 玩家.
   * @return 消息.
   */
  public ResMessage resGameInfo(Player player, int time, List<MemInfo> memInfos) {
    ResGameInfoMsg msg = new ResGameInfoMsg();
    if (player.curRoom instanceof BlackjackRoom && player.curSeat != null
        && player.curTable != null) {
      BlackjackTable table = (BlackjackTable) player.curTable;


      CardInfoDto bankCardInfo = new CardInfoDto();
      if (EmptyUtil.listIsNotEmpty(table.getBankerCards())) {
        List<Integer> bankCards = new ArrayList<>(5);
        if (table.getStatus() != GameStatus.BILL) {
          bankCards.add(table.getBankerCards().get(0).ordinal());
          bankCardInfo.setCards(bankCards);
          bankCardInfo.setCardsType(BlackjackCardsType.NORMAL.getType());
        } else {
          for (BlackjackCard card : table.getBankerCards()) {
            bankCards.add(card.ordinal());
          }

          bankCardInfo.setCards(bankCards);
          if (table.getBankerTypeAndPoint() != null
              && table.getBankerTypeAndPoint().getCardsType() != null) {
            bankCardInfo.setCardsType(table.getBankerTypeAndPoint().getCardsType().getType());
          }
        }
      }
      GameInfoDto gameInfo = new GameInfoDto();

      gameInfo.setBankCardInfo(bankCardInfo);

      gameInfo.setCardNum(table.getCards().size());

      List<SeatInfoDto> seatInfos = toSeatInfoDtos(table, false);

      gameInfo.setSeatInfos(seatInfos);

      gameInfo.setState(table.getStatus().getVal());

      gameInfo.setTime(time);
      gameInfo.setOrder(table.getActiveSeatOrder());
      gameInfo.setCardSeatOrder(table.getActiveCardOrder());

      msg.setGameInfo(gameInfo);

      BlackjackRoom room = (BlackjackRoom) player.curRoom;
      RoomInfo roomInfo = getRoomInfoByInstanceId(room.getInstanceId());
      msg.setRoomInfo(roomInfo);

      msg.setMems(memInfos);
    }
    return msg;
  }

  /**
   * 向同桌的玩家(包括自己)发送消息.
   * 
   * @param table .
   * @param msg .
   */
  private void noticeAllTablePlayersMsg(BlackjackTable table, ResMessage msg) {
    table.setSerial(table.getSerial() + 1);
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 向同桌的玩家(包括自己)发送消息.
   * 
   * @param table .
   * @param msg .
   */
  private void noticeTablePlayersMsgExcludeSelf(BlackjackTable table, ResMessage msg,
      long fromPlayerId) {
    List<? extends AbstractSeat> seats = table.seats();
    for (int i = 0; i < seats.size(); i++) {
      AbstractSeat seat = seats.get(i);
      long playerId = seat.getPlayerId();
      if (playerId > 0 && playerId != fromPlayerId) {
        msgWriter.writeMsg(playerId, msg);
      }
    }
  }

  /**
   * 发送其他人进入桌子消息.
   * 
   * @param seat 座位信息.
   */
  public void noticeEnterTableMsg(BlackjackSeat seat) {
    NoticeEnterTableMsg msg = new NoticeEnterTableMsg();
    msg.setMem(seat.getTable().getRoom().memInfo(seat.getPlayerId()));
    noticeTablePlayersMsgExcludeSelf(seat.getTable(), msg, seat.getPlayerId());
  }

  /**
   * 发送退出桌子消息.
   * 
   * @param seat 座位信息.
   */
  public void noticeExitTableMsg(BlackjackSeat seat) {
    NoticeExitTableMsg msg = new NoticeExitTableMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    noticeTablePlayersMsgExcludeSelf(seat.getTable(), msg, seat.getPlayerId());
  }

  /**
   * 通知被踢出房间 .
   *
   * @author abin
   * @date 2018年3月22日 下午5:20:36
   * @param player 玩家.
   */
  public void noticeKickoutRoom(Player player) {
    NoticeKickoutRoomMsg msg = new NoticeKickoutRoomMsg();
    msgWriter.writeMsg(player, msg);
  }


  /**
   * 通知被踢出桌子 .
   *
   * @author abin
   * @date 2018年3月22日 下午5:20:23
   * @param player 玩家.
   */
  public void noticeKickoutTable(Player player) {
    NoticeKickoutTableMsg msg = new NoticeKickoutTableMsg();
    msgWriter.writeMsg(player, msg);
  }

  /**
   * 发送游戏阶段 .
   *
   * @author abin
   * @date 2018年3月24日 下午2:42:10
   * @param table 桌子信息.
   * @param time 时间.
   */
  public void noticeGameStage(BlackjackTable table, int time) {
    NoticeStageTimeMsg msg = new NoticeStageTimeMsg();
    msg.setTime(time);
    msg.setState(table.getStatus().getVal());

    table.setSerial(table.getSerial() + 1);
    msg.setSerial(table.getSerial());
    noticeAllTablePlayersMsg(table, msg);
  }

  /**
   * 用户下注 -通知.
   *
   * @author abin
   * @date 2018年3月26日 上午10:11:14
   * @param seat 座位.
   * @param bet 下注筹码.
   */
  public void noticePlayerBet(BlackjackSeat seat, long bet) {
    NoticePlayerBetMsg msg = new NoticePlayerBetMsg();
    msg.setBet(bet);
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    msg.setTotalChips(seat.getTotalChips());

    seat.getTable().setSerial(seat.getTable().getSerial() + 1);
    msg.setSerial(seat.getTable().getSerial());

    noticeAllTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 用户下注结束-通知 .
   *
   * @author abin
   * @date 2018年3月26日 上午10:30:03
   * @param seat 座位信息
   */
  public void noticePlayerBetOver(BlackjackSeat seat) {
    NoticePlayerBetOverMsg msg = new NoticePlayerBetOverMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());

    seat.getTable().setSerial(seat.getTable().getSerial() + 1);
    msg.setSerial(seat.getTable().getSerial());
    noticeAllTablePlayersMsg(seat.getTable(), msg);
  }



  /**
   * 发牌-通知.
   *
   * @author abin
   * @date 2018年3月26日 上午11:56:16
   * @param table 桌子信息.
   */
  public void noticeDealCardStage(BlackjackTable table) {
    // 发牌阶段 1明1暗，所以指发一张牌
    CardInfoDto bankCardInfo = new CardInfoDto();
    List<Integer> bankCards = new ArrayList<>(1);
    bankCards.add(table.getBankerCards().get(0).ordinal());
    bankCardInfo.setCards(bankCards);
    bankCardInfo.setCardsType(BlackjackCardsType.NORMAL.getType());
    NoticeStageDealCardMsg msg = new NoticeStageDealCardMsg();
    msg.setBankCardInfo(bankCardInfo);

    // 玩家一明一暗，所以发两张牌
    List<SeatInfoDto> seatInfos = toSeatInfoDtos(table, false);

    msg.setSeatInfos(seatInfos);
    msg.setCardNum(table.getCards().size());

    table.setSerial(table.getSerial() + 1);
    msg.setSerial(table.getSerial());

    noticeAllTablePlayersMsg(table, msg);
  }

  /**
   * 保险结果 - 通知 .
   *
   * @author abin
   * @date 2018年3月26日 下午3:39:27
   * @param table 桌子.
   * @param isBlackjack 是否黑杰克.
   */
  public void noticeStageInsuranceBill(BlackjackTable table, boolean isBlackjack) {
    NoticeStageInsuranceBillMsg msg = new NoticeStageInsuranceBillMsg();
    msg.setBlackjack(isBlackjack);

    List<SeatInfoForInsuranceDto> seatInfos = new ArrayList<>(table.getSeats().size());
    for (BlackjackSeat seat : table.getSeats()) {
      if (seat.getPlayerId() > 0 && seat.isHasBet() && seat.isHasInsurance()) { // 只发送参与保险的结果.
        SeatInfoForInsuranceDto dto = new SeatInfoForInsuranceDto();
        dto.setInsuranceBet(seat.getInsuranceBet());
        dto.setOrder(seat.getOrder());
        dto.setPlayerId(seat.getPlayerId());
        dto.setTotalChips(seat.getTotalChips());
        dto.setChangeChips(seat.getChangeBet());
        seatInfos.add(dto);
      }
    }
    msg.setSeatInfos(seatInfos);

    table.setSerial(table.getSerial() + 1);
    msg.setSerial(table.getSerial());

    noticeAllTablePlayersMsg(table, msg);
  }

  private CardSeatInfoDto toCardSeatInfoDto(BlackjackCardSeat cardSeat) {
    CardSeatInfoDto cardSeatInfoDto = new CardSeatInfoDto();
    cardSeatInfoDto.setBet(cardSeat.getBet());
    cardSeatInfoDto.setBill(cardSeat.isBill());
    cardSeatInfoDto.setCardSeatOrder(cardSeat.getCardSeatOrder());

    CardInfoDto cardInfo = new CardInfoDto();
    List<Integer> cards = new ArrayList<>(2);
    for (BlackjackCard card : cardSeat.getPlayerCards()) {
      cards.add(card.ordinal());
    }
    cardInfo.setCards(cards);
    if (cardSeat.getCardTypeAndPoint() != null
        && cardSeat.getCardTypeAndPoint().getCardsType() != null) {
      cardInfo.setCardsType(cardSeat.getCardTypeAndPoint().getCardsType().getType());
    }

    cardSeatInfoDto.setCardInfo(cardInfo);
    return cardSeatInfoDto;
  }

  private List<SeatInfoDto> toSeatInfoDtos(BlackjackTable table, boolean includeNoBet) {
    List<SeatInfoDto> seatInfoDtos = new ArrayList<>();

    for (BlackjackSeat seat : table.getSeats()) {
      if (seat.getPlayerId() > 0) { // 只同步下注人的牌组
        if (!includeNoBet) {
          if (!seat.isHasBet()) {
            continue;
          }
        }
        SeatInfoDto seatInfoDto = new SeatInfoDto();
        seatInfoDto.setOrder(seat.getOrder());
        seatInfoDto.setPlayerId(seat.getPlayerId());
        seatInfoDto.setPlayerName(seat.getPlayerName());
        seatInfoDto.setSex(seat.getSex());
        seatInfoDto.setState(seat.getState().val);
        seatInfoDto.setTotalChips(seat.getTotalChips());
        seatInfoDto.setHasBet(seat.isHasBet());
        seatInfoDto.setHasInsurance(seat.isHasInsurance());

        List<CardSeatInfoDto> cardSeatInfoDtos = new ArrayList<>(3);

        for (BlackjackCardSeat cardSeat : seat.getCardSeats()) {
          CardSeatInfoDto cardSeatInfoDto = toCardSeatInfoDto(cardSeat);
          cardSeatInfoDtos.add(cardSeatInfoDto);
        }

        seatInfoDto.setCardSeatInfoDtos(cardSeatInfoDtos);
        seatInfoDtos.add(seatInfoDto);
      }
    }
    return seatInfoDtos;
  }

  /**
   * 玩家下保险-通知.
   *
   * @author abin
   * @date 2018年3月26日 上午10:32:58
   * @param seat 座位.
   */
  public void noticePlayerInsurance(BlackjackSeat seat) {
    NoticePlayerInsuranceMsg msg = new NoticePlayerInsuranceMsg();
    msg.setInsuranceBet(seat.getInsuranceBet());
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    msg.setTotalChips(seat.getTotalChips());

    seat.getTable().setSerial(seat.getTable().getSerial() + 1);
    msg.setSerial(seat.getTable().getSerial());

    noticeAllTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 玩家双倍-通知 .
   *
   * @author abin
   * @date 2018年3月27日 下午1:52:42
   * @param seat 座位.
   * @param cardSeat 牌座位.
   */
  public void noticePlayerDoubleDown(BlackjackSeat seat, BlackjackCardSeat cardSeat) {
    NoticePlayerDoubleDownMsg msg = new NoticePlayerDoubleDownMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    msg.setTotalChips(seat.getTotalChips());
    msg.setChangeChips(seat.getChangeBet());
    CardSeatInfoDto cardSeatInfoDto = toCardSeatInfoDto(cardSeat);
    msg.setCardSeat(cardSeatInfoDto);

    msg.setCardSeatOrder(seat.getTable().getActiveCardOrder());

    seat.getTable().setSerial(seat.getTable().getSerial() + 1);
    msg.setSerial(seat.getTable().getSerial());

    noticeAllTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 玩家分牌-通知 .
   *
   * @author abin
   * @date 2018年3月27日 下午4:47:12
   * @param seat 座位信息.
   */
  public void noticePlayerSplit(BlackjackSeat seat) {
    NoticePlayerSplitMsg msg = new NoticePlayerSplitMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    msg.setTotalChips(seat.getTotalChips());

    List<CardSeatInfoDto> cardSeatInfoDtos = new ArrayList<>(3);
    for (BlackjackCardSeat cardSeat : seat.getCardSeats()) {
      CardSeatInfoDto cardSeatInfoDto = toCardSeatInfoDto(cardSeat);
      cardSeatInfoDtos.add(cardSeatInfoDto);
    }

    msg.setCardSeats(cardSeatInfoDtos);

    msg.setCardSeatOrder(seat.getTable().getActiveCardOrder());

    seat.getTable().setSerial(seat.getTable().getSerial() + 1);
    msg.setSerial(seat.getTable().getSerial());

    noticeAllTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 发送补牌-通知 .
   *
   * @author abin
   * @date 2018年3月28日 上午10:02:02
   * @param seat 座位信息.
   * @param cardSeat 卡牌座位信息.
   */
  public void noticePlayerHit(BlackjackSeat seat, BlackjackCardSeat cardSeat) {
    NoticePlayerHitMsg msg = new NoticePlayerHitMsg();
    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    msg.setTotalChips(seat.getTotalChips());
    msg.setChangeChips(seat.getChangeBet());
    CardSeatInfoDto cardSeatInfoDto = toCardSeatInfoDto(cardSeat);
    msg.setCardSeat(cardSeatInfoDto);

    msg.setCardSeatOrder(seat.getTable().getActiveCardOrder());

    seat.getTable().setSerial(seat.getTable().getSerial() + 1);
    msg.setSerial(seat.getTable().getSerial());

    noticeAllTablePlayersMsg(seat.getTable(), msg);
  }

  /**
   * 站起-通知 .
   *
   * @author abin
   * @date 2018年3月28日 上午10:29:48
   * @param seat 座位信息.
   */
  public void noticePlayerStand(BlackjackSeat seat) {
    NoticePlayerStandMsg msg = new NoticePlayerStandMsg();

    msg.setOrder(seat.getOrder());
    msg.setPlayerId(seat.getPlayerId());
    msg.setTotalChips(seat.getTotalChips());

    msg.setCardSeatOrder(seat.getTable().getActiveCardOrder());

    seat.getTable().setSerial(seat.getTable().getSerial() + 1);
    msg.setSerial(seat.getTable().getSerial());

    noticeAllTablePlayersMsg(seat.getTable(), msg);
  }


  /**
   * 通知玩家操作. .
   *
   * @author abin
   * @date 2018年3月28日 下午2:12:00
   * @param currentSeat 当前座位.
   * @param currentCardSeat 当前虚拟座位.
   * @param time 阶段时间.
   */
  public void noticeStagePlayerOp(BlackjackSeat currentSeat, BlackjackCardSeat currentCardSeat,
      int time) {
    NoticeStagePlayerOpMsg msg = new NoticeStagePlayerOpMsg();
    msg.setCardSeatOrder(currentCardSeat.getCardSeatOrder());
    msg.setOrder(currentSeat.getOrder());
    msg.setPlayerId(currentSeat.getPlayerId());
    msg.setTime(time);

    currentSeat.getTable().setSerial(currentSeat.getTable().getSerial() + 1);
    msg.setSerial(currentSeat.getTable().getSerial());

    noticeAllTablePlayersMsg(currentSeat.getTable(), msg);
  }

  /**
   * 通知庄家操作结果 .
   *
   * @author abin
   * @date 2018年3月28日 下午2:07:40
   * @param table 桌子.
   */
  public void noticeStageBankerOp(BlackjackTable table) {
    CardInfoDto bankCardInfo = new CardInfoDto();
    List<Integer> bankCards = new ArrayList<>(5);
    for (BlackjackCard card : table.getBankerCards()) {
      bankCards.add(card.ordinal());
    }
    bankCardInfo.setCards(bankCards);
    bankCardInfo.setCardsType(table.getBankerTypeAndPoint().getCardsType().getType());

    NoticeStageBankerOpMsg msg = new NoticeStageBankerOpMsg();
    msg.setBankCardInfo(bankCardInfo);

    table.setSerial(table.getSerial() + 1);
    msg.setSerial(table.getSerial());

    noticeAllTablePlayersMsg(table, msg);
  }

  /**
   * 结算阶段-通知 .
   *
   * @author abin
   * @date 2018年3月29日 上午11:48:07
   * @param table 桌子.
   */
  public void noticeStageBill(BlackjackTable table) {
    NoticeStageBillMsg msg = new NoticeStageBillMsg();
    List<SeatInfoForBillDto> seatInfos = new ArrayList<>();
    for (BlackjackSeat seat : table.getSeats()) {
      if (seat.getPlayerId() > 0 && seat.isHasBet() && !seat.isAllCardSeatBilled()) {
        SeatInfoForBillDto seatDto = new SeatInfoForBillDto();
        seatDto.setChangeChips(seat.getChangeBet());
        seatDto.setOrder(seat.getOrder());
        seatDto.setPlayerId(seat.getPlayerId());
        seatDto.setTotalChips(seat.getTotalChips());
        seatInfos.add(seatDto);
      }
    }
    msg.setSeatInfos(seatInfos);

    table.setSerial(table.getSerial() + 1);
    msg.setSerial(table.getSerial());

    noticeAllTablePlayersMsg(table, msg);
  }

}
